/*
 * $Id: html.h,v 1.15 1995/03/29 20:26:52 chris Exp $
 */

#ifndef HTML_H
#define HTML_H

/*
 * A simple list of attributes that might be in an element.
 */
typedef struct attribute {
    atom aAtom;			/* Attribute atom */
    int lineno;			/* attribute line number */
    int flags;			/* Special flags */
#define DQUOTEDVALUE	0x1	/* attribute value was double-quoted */
#define SQUOTEDVALUE	0x2	/* attribute value was single-quoted */
    char *name;			/* Name like 'href' */
    char *data;			/* string of value (NULL if no value defined) */
    struct attribute *next;	/* unlimited number of attributes */
} Attribute;

/*
 * A block is our basic data structure.  A block can be of
 * four types, including an element tag, character text, a comment,
 * or a doctype declaration.  
 *
 * We build a tree of blocks.  Each block can have a set of children
 * below it, plus a set of siblings off to its right.
 */

typedef struct block {
    int type;
#define TAG		1
#define PCDATA		2
#define CMNT		3
#define DOCTYPE		4
    int flags;			/* Special flags */
#define OPTCLOSE	0x01	/* input lacked optional close for this block */
#define OPTTAG		0x02	/* input lacked this optional tag (HTML....) */
#define SHRTTAG		0x04	/* This tag was closed with shorttag </> */
#define PRETTYSTART	0x10	/* This tag was followed by a newline */
#define PRETTYEND	0x20	/* This tag end was followed by a newline */
    atom bAtom;			/* atom for this element */
    char *data;			/* Text or tag name */
    int lineno;			/* tag start Input file line number */
    Attribute *attrs;
    struct block *next_sib;	/* sibling on right */
    struct block *children;	/* children below */
    struct block *parent;
} Block;

/*
 * Structure for delivering error messages
 */
struct error {
    int lineno;			/* Line number of offending string */
    int severity;		/* How severe the error is */
    char *text;			/* Text of offending character */
    int type;			/* Error type */
    char *message;		/* Generated error message */
};

#define MAX_ERROR_LEN 1024

/*
 * Error severities:
 *    E_INFORMATION - usually notes optional missing elements being provided
 *    E_WARNING - allowing something that violates the HTML spec
 *    E_SEVERE - a syntax error has been ignored.  Probably failure
 *    E_CRASH - parse engine is trashed - continued input not possible
 */
#define E_INFORMATION			0
#define E_WARNING			1
#define E_SEVERE			2
#define E_CRASH				3

#define E_UNEXPECTEDCHAR		0
#define E_NOMEM				1
#define E_MISSINGHTML			2
#define E_MISSINGHEAD			3
#define E_MISSINGBODY			4
#define E_CANTCLOSE			5
#define E_BADPARENT			6
#define E_NOCLOSE			7
#define E_NOOPEN			8
#define E_UNKNOWNELE			9
#define E_SYNTAX			10
#define E_MISSINGTITLE			11
#define E_PROGRAMMING			12
#define E_UNKNOWNATTR			13
#define E_INVALIDEATTR			14
#define E_MISSINGATTR			15
#define E_UNKNOWNENTITY			16
#define E_ATTR				17
#define E_MISSINGQUOTE			18
#define E_EXTRATAG			19
#define E_COMMENTTERM			20

/*
 * E_UNEXPECTEDCHAR
 *	An unexepected (or illegal) character has appeared in the
 *	input stream.
 *
 * E_NOMEM
 *	An attempt to allocate memory has failed.
 *
 * E_MISSINGHTML
 *	The opening <HTML> (which is optional) was not supplied.
 *
 * E_MISSINGHEAD
 *	The opening <HEAD> (which is optional) was not supplied.
 *
 * E_MISSINGBODY
 *	The opening <BODY> (which is optional) was not supplied.
 *
 * E_CANTCLOSE
 *	We have an element that is parented by an element which
 *	requires a manditory close.  This element is not an
 *	appropriate child for this parent.  We parent the element
 *	anyway.
 *
 * E_BADPARENT
 *	While moving up the list closing elements and looking for
 *	a valid parent, we found an element requiring a manditory
 *	close.  This is a syntax error.  We will parent the child
 *	at the lowest level and go on.
 *
 * E_NOCLOSE
 *	An element is missing its mandatory end tag.
 *
 * E_NOOPEN
 *	An end tag has no corresponding opening element.
 *
 * E_UNKNOWNELE
 *	An unknown element has been found.  We assume that these
 *	must be terminated and can contain any other elements.
 *
 * E_SYNTAX
 *	Yacc has detected a syntax error.
 *
 * E_MISSINGTITLE
 *	HTML requires a title.  This error indicates that none
 *	was provided.
 *
 * E_PROGRAMMING
 *	An illegal usage of one of the builtin programming functions.
 *
 * E_UNKNOWNATTR
 *	An unknown attribute has been found.
 *
 * E_INVALIDEATTR
 *	Attribute is not allowed in the markup it is found in.
 *
 * E_MISSINGATTR
 *	Required attribute is missing in this markup
 *
 * E_UNKNOWNENTITY
 *	Unknown entity name
 *
 * E_ATTR
 *	Syntax error in attributes.
 *
 * E_MISSINGQUOTE
 *	Apparently missing quote in attribute list.  Although this
 *	may have been someone embedding a '>' in the quoted string,
 *	it is more often just an error, so we try to fix it.
 *
 * E_EXTRATAG
 *	A tag that should only appear once (like <HTML> or <BODY>)
 *	has appeared twice.
 *
 * E_COMMENTTERM
 *	An unterminated comment was found in the source file.
 *	Generally, this produces bad parse trees.
 *
 */

typedef int (*HTMLErrorHandler)(struct error *errp);

extern void HTMLParseBegin();
extern void HTMLParseDo(FILE *);
extern Block *HTMLParseEnd();
extern void HTMLFreeParseTree(Block *);
extern HTMLErrorHandler HTMLSetErrorHand(HTMLErrorHandler);

/* Create new blocks and free them */
extern Block *HTMLNewBlock(int type, char *data, int lineno);
extern void HTMLFreeBlock(Block *old);
extern void HTMLFreeTree(Block *old);

/* Create new attributes and free them */
extern Attribute *HTMLNewAttr(char *name, char *value, int lineno);
extern void HTMLFreeAttribute(Attribute *old);
extern void HTMLFreeAttributeList(Attribute *old);

/* Get/Set/Remove attributes for a block */
extern char *HTMLGetAttr(Block *bp, char *name);
extern void HTMLSetAttr(Block *bp, char *name, char *data);
int HTMLRemoveAttr(Block *bp, char *name);

/* Insert and remove blocks from the tree */
extern void HTMLInsertBlock(Block *bp, Block *parent, Block *predecessor);
extern Block *HTMLRemoveBlock(Block *bp);

/* Macros for getting block information */
#define HTMLGetBAtom(block)		((block)->bAtom)
#define HTMLGetBType(block)		((block)->type)
#define HTMLGetBData(block)		((block)->data)
#define HTMLGetBParent(block)		((block)->parent)
#define HTMLGetBChild(block)		((block)->children)
#define HTMLGetBSib(block)		((block)->next_sib)
#define HTMLGetBLineno(block)		((block)->lineno)
#define HTMLGetBFlags(block)		((block)->flags)
#define HTMLGetBAttrs(block)		((block)->type == TAG ? \
					    (block)->attrs : \
						(Attribute *)0)

/* Macros for setting block information */
#define HTMLSetBAtom(block, _atom)		((block)->bAtom = (_atom))
#define HTMLSetBType(block, _type)		((block)->type = (_type))
#define HTMLSetBData(block, _data)		((block)->data = (_data))
#define HTMLSetBParent(block, _parent)		((block)->parent = (_parent))
#define HTMLSetBChild(block, _child)		((block)->children = (_child))
#define HTMLSetBSib(block, _sib)		((block)->next_sib = (_sib))
#define HTMLSetBLineno(block, _lineno)		((block)->lineno = (_lineno))
#define HTMLSetBAttrs(block, _attrs)		((block)->attrs = (_attrs))

#define HTMLAddBFlags(block, _flags)		((block)->flags |= (_flags))
#define HTMLDeleteBFlags(block, _flags)		((block)->flags &= ~(_flags))

/* Macros for getting attribute information */
#define HTMLGetAAtom(attribute)		((attribute)->aAtom)
#define HTMLGetAName(attribute)		((attribute)->name)
#define HTMLGetAData(attribute)		((attribute)->data)
#define HTMLGetANext(attribute)		((attribute)->next)
#define HTMLGetALineno(attribute)	((attribute)->lineno)

/* Macros for setting attribute information */
#define HTMLSetAAtom(attribute, _atom)		((attribute)->aAtom = (_atom))
#define HTMLSetAName(attribute, _name)		((attribute)->name = (_name))
#define HTMLSetAData(attribute, _data)		((attribute)->data = (_data))
#define HTMLSetANext(attribute, _next)		((attribute)->next = (_next))
#define HTMLSetALineno(attr, _lineno)		((attr)->lineno = (_lineno))

#endif
